/*
 * @Author       : Zhao Lvhua zhaolh@linkcharging.com
 * @Date         : 2024-09-02 01:04:00
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:02:23
 * @FilePath     : \openchaoji-corelib\shared\src\OpenChaoJi_utility_transport_gbt27930_a_recv.c
 * @Description  :
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "OpenChaoJi_utility_transport_gbt27930_a.h"
#include "OpenChaoJi_utility_transport_gbt27930_a_private.h"

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)

extern bool s_transport_debug_enable;

/*
* @brief: A类系统对于可靠消息状态处理方法，对于可靠长消息、可靠短消息的接收发送状态机的处理，一般建议不超过5ms调用一次
* @param {OpenChaoJi_gbt27930_a_rmcb *} rmcb 可靠确认消息体的指针
* @return 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_utility_transport_gbt27930_a_service(struct OpenChaoJi_gbt27930_a_rmcb * rmcb)
{
	//需要确认长消息处理
    if (rmcb->lm_send_state != LM_SEND_IDLE)
    {
        OpenChaoJi_transport_gbt27930_a_rlm_send_process(NULL,rmcb);
    }

	if (rmcb->lm_recv_state != LM_RECV_S0_IDLE)
    {
        OpenChaoJi_transport_gbt27930_a_rlm_recv_process(NULL,rmcb);
    }

    return 0;
}

/*
* @brief: 获取A类系统CAN底层数据帧类型，根据数据帧类型输入到对应的消息控制块中
* @param {can_pdu *} pdu 可靠确认消息体的指针
* @return 不可靠消息返回0，可靠消息返回1。
*/
int16_t OpenChaoJi_transport_gbt27930_a_get_canframe_type(struct can_pdu * pdu)
{
	uint16_t pgn = ((uint16_t)(pdu->can_id.bit.pf))<<8;

	if (pgn == PGN_TPCM || pgn == PGN_TPDT)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}


/*
* @brief: gbt27930 A类系统不需要确认短消息的接收处理
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*} 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_a_urm_input(struct can_pdu * pdu,  struct OpenChaoJi_gbt27930_a_urmcb  * urmcb)
{

	urmcb->sm_recv_buf = *pdu;
	urmcb->sm_recved_flag = 1;

	return 0;
}



/*
* @brief: gbt27930 A类系统不需要确认短消息的接收处理
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*} 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_a_rm_input(struct can_pdu * pdu,  struct OpenChaoJi_gbt27930_a_rmcb  * rmcb)
{

	uint16_t pgn = ((uint16_t)(pdu->can_id.bit.pf))<<8;
	uint8_t ack_type = 0;

	if (pgn == PGN_TPCM)
	{
		ack_type = pdu->data[0];
		if (ack_type == TPCM_RTS)
		{
			OpenChaoJi_transport_gbt27930_a_rlm_recv_process(pdu, rmcb);
		}
		else if (ack_type == TPCM_CTS)
		{
			rmcb->rcved_ack_flag = TPCM_CTS;
			OpenChaoJi_transport_gbt27930_a_rlm_send_process(pdu, rmcb);
            rmcb->rcved_ack_flag = TPCM_INVALID_VALUE;//复位
		}
		else if (ack_type == TPCM_EndACK)
		{
			rmcb->rcved_ack_flag = TPCM_EndACK;
			OpenChaoJi_transport_gbt27930_a_rlm_send_process(pdu, rmcb);
            rmcb->rcved_ack_flag = TPCM_INVALID_VALUE;//复位
		}
		else if (ack_type == TPCM_ABORT)
		{
			rmcb->rcved_ack_flag = TPCM_ABORT;
			OpenChaoJi_transport_gbt27930_a_rlm_send_process(NULL, rmcb);
			OpenChaoJi_transport_gbt27930_a_rlm_recv_process(NULL, rmcb);
            rmcb->rcved_ack_flag = TPCM_INVALID_VALUE;//复位
		}
		else
		{
			return -1;
		}
	}
	else if (pgn == PGN_TPDT)
	{
		OpenChaoJi_transport_gbt27930_a_rlm_recv_process(pdu, rmcb);
	}

	return 0;
}

int16_t OpenChaoJi_utility_transport_gbt27930_a_got_urm_msg(struct OpenChaoJi_gbt27930_a_urmcb * urmcb, struct can_data * recv_data)
{
	if (urmcb == NULL){
		//error
        LOG_ERR("transportrecv urmcb space is null");
		return -1;
	}

	//不需要确认短消息
    if (urmcb->sm_recved_flag == 1)
    {
		recv_data->data = urmcb->sm_recv_buf.data;
        recv_data->len = urmcb->sm_recv_buf.can_dlc;
		recv_data->can_id = urmcb->sm_recv_buf.can_id;
        urmcb->sm_recved_flag = 0;

        return 0;
    }

	return -1;
}

int16_t OpenChaoJi_utility_transport_gbt27930_a_got_rm_msg(struct OpenChaoJi_gbt27930_a_rmcb  * rmcb, struct can_data * recv_data)
{
	if (rmcb == NULL){
		//error
        LOG_ERR("transportrecv rmcb space is null");
		return -1;
	}

    //可靠长消息
    if (rmcb->lm_recved_flag == 1)
    {
        recv_data->data = rmcb->lm_recv_buf;
        recv_data->len = rmcb->lm_recv_tbytes;
        rmcb->lm_recved_flag = 0;

		recv_data->can_id.bit.sa = rmcb->dest_addr;
		recv_data->can_id.bit.ps = 	rmcb->src_addr;
		recv_data->can_id.bit.pf = 	(rmcb->lm_recv_pgn>>8)&0xff;
		recv_data->can_id.bit.dp = 0;
		recv_data->can_id.bit.edp = 0;
		recv_data->can_id.bit.p = 7;
		recv_data->can_id.bit.rsvd = 0;

        return 0;
    }
	return -1;
}

int16_t OpenChaoJi_transport_gbt27930_a_rlm_recv_process(struct can_pdu * pdu, struct OpenChaoJi_gbt27930_a_rmcb * rmcb)
{

	uint8_t fram_idx;

	struct OpenChaoJi_gbt27930_a_rmcb *Msgcb = rmcb;

	switch (Msgcb->lm_recv_state)
	{
		case LM_RECV_S0_IDLE:
			if (pdu != NULL)
			{
				uint16_t pgn = ((uint16_t)(pdu->can_id.bit.pf))<<8;

				if (pgn == PGN_TPCM && pdu->data[0] == 0x10)
				{
					Msgcb->lm_tfra = pdu->data[3];
					Msgcb->lm_recv_tbytes = pdu->data[1] + (((uint16_t)(pdu->data[2]))<<8);
					Msgcb->lm_recv_pgn = pdu->data[5] + (((uint32_t)(pdu->data[6]))<<8) + (((uint32_t)(pdu->data[7]))<<16);

					//为长帧信息帧申请内存
			        Msgcb->lm_recv_buf = (uint8_t *)OpenChaoJi_os_malloc(Msgcb->lm_tfra*7);//add redundancy
					if (Msgcb->lm_recv_buf == NULL) {
						return -1;
						//err
					}

					Msgcb->lm_recv_n = 1;
					Msgcb->lm_recv_k = Msgcb->lm_tfra;
					gbt27930_a_rlm_send_cts(Msgcb);

					Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
					Msgcb->lm_recv_lms_t3_tick = OpenChaoJi_os_get_ticks();
					Msgcb->lm_recv_no = 0;
					Msgcb->lm_recv_num = 0;
					Msgcb->lm_recved_tfra = 0;
					Msgcb->lm_recv_err_cnt = 0;

					Msgcb->lm_recv_state = LM_RECV_S1_DATA_RECEIVING;
				}
			}
			break;

		case LM_RECV_S1_DATA_RECEIVING:

			if (pdu != NULL)
			{
				uint16_t pgn = ((uint16_t)(pdu->can_id.bit.pf))<<8;
				if (pgn == PGN_TPCM)
				{
					if (pdu->data[0] == TPCM_RTS)
					{
						Msgcb->lm_tfra = pdu->data[3];
						Msgcb->lm_recv_tbytes = pdu->data[1] + (((uint16_t)(pdu->data[2]))<<8);

						Msgcb->lm_recv_pgn = pdu->data[5]
												+ (((uint32_t)(pdu->data[6]))<<8)
												+ (((uint32_t)(pdu->data[7]))<<16);

						//为长帧信息帧申请内存
						//OPEN_CHAOJI_MEM_FREE_CHECK(Msgcb->lm_recv_buf);
                        OpenChaoJi_os_free(Msgcb->lm_recv_buf);
				        Msgcb->lm_recv_buf = (uint8_t *)OpenChaoJi_os_malloc(Msgcb->lm_tfra*7);//add redundancy
						if (Msgcb->lm_recv_buf == NULL) {
							return -1;
							//err
						}

						Msgcb->lm_recv_n = 1;
						Msgcb->lm_recv_k = Msgcb->lm_tfra;
						gbt27930_a_rlm_send_cts(Msgcb);

						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						//Msgcb->lm_recv_lms_t3_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_no = 0;
						Msgcb->lm_recv_num = 0;
						Msgcb->lm_recved_tfra = 0;
						Msgcb->lm_recv_err_cnt = 0;

						Msgcb->lm_recv_state = LM_RECV_S1_DATA_RECEIVING;
					}
				}
				else if (pgn == PGN_TPDT)
				{
					fram_idx = pdu->data[0];
					//长消息已接收完recv_tfra=lm_tfra
					if (Msgcb->lm_recved_tfra == Msgcb->lm_tfra)
					{
						//recv_tfra置为lm_tfra,发送LM_EndofACK . 进 入 S 2
						gbt27930_a_rlm_send_endofack(Msgcb);
						Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
						Msgcb->lm_recved_flag = 1;
					}

					//接收帧序号不连续，漏收报文，n>recv_  no+1且recv_tfra < lm_tfra
					if ((fram_idx > (Msgcb->lm_recv_no + 1)) && (Msgcb->lm_recved_tfra < Msgcb->lm_tfra))
					{
						//发送   LM_ACK(recv_no+1, k),开启 LMS_T2,recv_num置零，保持Sl
						Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
						Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
						gbt27930_a_rlm_send_cts(Msgcb);
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
						Msgcb->lm_recv_num = 0;
					}

					//接收长消息最后一帧，n =  recv_no+1且 recv_tfra+1 = m_tfra
					if ((fram_idx >= (Msgcb->lm_recv_no + 1)) && ((Msgcb->lm_recved_tfra + 1) == Msgcb->lm_tfra))
					{
						//recv_tfra置为 lm_tfra,发送LM_EndofACK,进入S2
						memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recved_tfra = Msgcb->lm_tfra;
						gbt27930_a_rlm_send_endofack(Msgcb);
						Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
						Msgcb->lm_recved_flag = 1;
					}

					//接收当前请求的最后一帧，n=recv   no+ 1且recv_num  ≥ k - 1 且 recv_tfra+1 < lm tfra
					if ((fram_idx > (Msgcb->lm_recv_no + 1))
						&& (Msgcb->lm_recv_num >= (Msgcb->lm_recv_k - 1))
						&& ((Msgcb->lm_recved_tfra + 1) < Msgcb->lm_tfra))
					{
						//recv_no置为 n , 发送LM_ACK(n+1,k),recv_num 置零，recv  _fra加1,LMS T2开启，保持S1
                        memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recv_no = fram_idx;
						Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
						Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
						gbt27930_a_rlm_send_cts(Msgcb);
						Msgcb->lm_recv_num = 0;
						++(Msgcb->lm_recved_tfra);
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
					}

					//未接收完 n =recv_no+1且recv_num<k—1且recv_tfra+1<lm_tfra
					if ((fram_idx == (Msgcb->lm_recv_no + 1))
						&& (Msgcb->lm_recv_num < (Msgcb->lm_recv_k - 1))
						&& ((Msgcb->lm_recved_tfra + 1) < Msgcb->lm_tfra))
					{
						//recv_no置为n,recv  _num加1,recv_tfra 加1,LMS_T2开启，保持S1
						memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recv_no = fram_idx;
						++Msgcb->lm_recv_num;
						++Msgcb->lm_recved_tfra;
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
					}
				}
			}
			//
			else if (Msgcb->rcved_ack_flag == TPCM_ABORT)
			{
				Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
			}

			//LMS_T2定时器到
			else if ((OpenChaoJi_os_get_ticks() - Msgcb->lm_recv_lms_t2_tick) >= Msgcb->lm_recv_lms_t2_intvl_ms)
			{
				//如果发送方  连续3次响应超时，发送LM_NACK,进入S2 , 否则发送LM_ACK(recv_no+1,k),重  置LMS T2,保持Sl
				Msgcb->lm_recv_err_cnt++;
				if (Msgcb->lm_recv_err_cnt >= 3)
				{
					gbt27930_a_rlm_sent_nack(Msgcb);
				}
				else
				{
					Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
					Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
					gbt27930_a_rlm_send_cts(Msgcb);
					Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
				}
			}

				//LMS_T3定时器到或主动中止传输
			else if (((OpenChaoJi_os_get_ticks() - Msgcb->lm_recv_lms_t3_tick) >= Msgcb->lm_recv_lms_t3_intvl_ms)
				|| (Msgcb->lm_recv_active_abort == 1))
			{
				//发送LM_NACK,进入S2
				gbt27930_a_rlm_sent_nack(Msgcb);
				Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
				Msgcb->lm_recv_active_abort = 0;
			}
			break;

		case LM_RECV_S2_CLOSE_CONN:
			//关闭LMS_T2、LMS_T3定时器(如开启),recv_no,err_cnt置零
			Msgcb->lm_recv_lms_t2_tick = 0;
			Msgcb->lm_recv_lms_t3_tick = 0;
			Msgcb->lm_recv_no = 0;
			Msgcb->lm_recv_err_cnt = 0;
			Msgcb->lm_recv_state = LM_RECV_S0_IDLE;
			break;

		default: break;
	}

	return 0;
}


//长消息发送连接
int16_t gbt27930_a_rlm_send_cts(struct OpenChaoJi_gbt27930_a_rmcb * rmcb)
{
	struct can_pdu pdu;
    int16_t res;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = (PGN_TPCM>>8);
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 7;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = TPCM_CTS;
	pdu.data[1] = rmcb->lm_recv_k;	//本次接收总帧数
	pdu.data[2] = rmcb->lm_recv_n;	//待接收起始帧序号
	pdu.data[3] = 0xff;
	pdu.data[4] = 0xff;
	pdu.data[5] = ((rmcb->lm_recv_pgn)&0xff);
	pdu.data[6] = ((rmcb->lm_recv_pgn >> 8)&0xff);
	pdu.data[7] = ((rmcb->lm_recv_pgn >> 16)&0xff);

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->a_rlm_conn[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}


//长消息发送连接
int16_t gbt27930_a_rlm_send_endofack(struct OpenChaoJi_gbt27930_a_rmcb * rmcb)
{
    int16_t res;
	struct can_pdu pdu;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = (PGN_TPCM>>8);
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 7;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = TPCM_EndACK;
	pdu.data[1] = ((rmcb->lm_recv_tbytes)&0xff);	//整个消息大小的字节数
	pdu.data[2] = ((rmcb->lm_recv_tbytes >> 8)&0xff);	//整个消息大小的字节数
	pdu.data[3] = rmcb->lm_tfra;
	pdu.data[4] = 0xff;
	pdu.data[5] = ((rmcb->lm_recv_pgn)&0xff);
	pdu.data[6] = ((rmcb->lm_recv_pgn >> 8)&0xff);
	pdu.data[7] = ((rmcb->lm_recv_pgn >> 16)&0xff);

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->a_rlm_end[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}


//长消息NACK发送
int16_t gbt27930_a_rlm_sent_nack(struct OpenChaoJi_gbt27930_a_rmcb * rmcb)
{
    int16_t res;
	struct can_pdu pdu;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = (PGN_TPCM>>8);
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 7;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = TPCM_ABORT;
	pdu.data[1] = 0xff;
	pdu.data[2] = 0xff;
	pdu.data[3] = 0xff;
	pdu.data[4] = 0xff;
	pdu.data[5] = ((rmcb->lm_recv_pgn)&0xff);
	pdu.data[6] = ((rmcb->lm_recv_pgn >> 8)&0xff);
	pdu.data[7] = ((rmcb->lm_recv_pgn >> 16)&0xff);

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->a_rlm_nack[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}

#endif
